﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using yiCommerce.Core;
using yiCommerce.Core.Domain.Customers;
using yiCommerce.Core.Domain.Orders;
using yiCommerce.Core.Domain.Payments;
using yiCommerce.Core.Domain.ShoppingCarts;
using yiCommerce.Models.Checkouts;
using yiCommerce.Models.Commons;
using yiCommerce.Service.Customers;
using yiCommerce.Service.Loggings;
using yiCommerce.Service.Orders;
using yiCommerce.Service.Payments;
using yiCommerce.Service.Pictures;
using yiCommerce.Service.Products;
using yiCommerce.Service.ShoppingCarts;

namespace yiCommerce.Controllers
{
    public class CheckoutController : Controller
    {
        private IProductVariantAttributeFormatter formatter;
        private IPictureService _pictureService;
        private IProductService _productService;
        private IWorkContext _workContext;
        private ICustomerService _customerService;
        private IPaymentService _paymentService;
        private IOrderProcessingService _orderProcessingService;
        private readonly ILogger _logger;
        private IOrderService _orderService;
        private IShoppingCartService _shoppingCartService;

        public CheckoutController(IProductVariantAttributeFormatter formatter, IPictureService pictureService,
                                  IProductService productService, IWorkContext workContext,
                                  ICustomerService customerService, IPaymentService paymentService,
                                  IOrderProcessingService orderProcessingService, ILogger logger,
                                  IOrderService orderService, IShoppingCartService shoppingCartService)
        {
            this.formatter = formatter;
            _pictureService = pictureService;
            _productService = productService;
            _workContext = workContext;
            _customerService = customerService;
            _paymentService = paymentService;
            _orderProcessingService = orderProcessingService;
            _logger = logger;
            _orderService = orderService;
            _shoppingCartService = shoppingCartService;
        }


        public ActionResult ShippingAddress()
        {
            //model
            var model = PrepareShippingAddressModel();
            ViewBag.Model = model;
            return View(model);
        }

        private IList<ShoppingCartItem> GetCustomerShoppingCartItems(int customerId)
        {
            return _shoppingCartService.GetShoppingCart(customerId);
        }

        #region shipping address
        private CheckoutShippingAddressModel PrepareShippingAddressModel()
        {
            var model = new CheckoutShippingAddressModel();
            model.ExistingAddresses = new List<AddressModel>();
            //existing addresses
            var addresses = _workContext.CurrentCustomer.Addresses.ToList();
            foreach (var address in addresses)
            {
                var addressModel = new AddressModel();
                addressModel.PrepareModel(address);
                model.ExistingAddresses.Add(addressModel);
            }

            //new address
            model.NewAddress=new AddressModel();
            model.NewAddress.PrepareNewModel();
            
            return model;
        }

        public ActionResult SelectShippingAddress(int addressId)
        {
            var address = _workContext.CurrentCustomer.Addresses.Where(a => a.Id == addressId).FirstOrDefault();
            if (address == null)
                return RedirectToAction("ShippingAddress");

            _workContext.CurrentCustomer.ShippingAddress = address;

            _customerService.UpdateCustomer(_workContext.CurrentCustomer);

            //return RedirectToRoute("CheckoutShippingMethod");
            //return RedirectToRoute("CheckoutPaymentMethod");
            return RedirectToAction("PaymentMethod");
        }

      

        #endregion


        #region paymentmethod
        public ActionResult PaymentMethod()
        {
            //validation
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.ToList();
            if (cart.Count == 0)
                return RedirectToRoute("ShoppingCart");



            if (_workContext.CurrentCustomer.IsGuest())
                return new HttpUnauthorizedResult();


            //model
            var paymentMethodModel = PreparePaymentMethodModel(cart);

            ViewBag.Model = paymentMethodModel;
            return View();
        }

        protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList<ShoppingCartItem> cart)
        {
            var model = new CheckoutPaymentMethodModel();
            model.PaymentMethods = new List<PaymentMethodModel>();

            var boundPaymentMethods = _paymentService.LoadActivePaymentMethods().ToList();

            foreach (var pm in boundPaymentMethods)
            {
               
                var pmModel = new PaymentMethodModel()
                {
                    //Name = pm.GetLocalizedFriendlyName(_localizationService, _workContext.WorkingLanguage.Id),
                    PaymentMethodSystemName =pm.SystemName,
                };
           

                model.PaymentMethods.Add(pmModel);
            }

            //find a selected (previously) payment method
            if (!String.IsNullOrEmpty(_workContext.CurrentCustomer.SelectedPaymentMethodSystemName))
            {
                var paymentMethodToSelect = model.PaymentMethods.ToList()
                    .Find(pm => pm.PaymentMethodSystemName.Equals(_workContext.CurrentCustomer.SelectedPaymentMethodSystemName, StringComparison.InvariantCultureIgnoreCase));
                if (paymentMethodToSelect != null)
                    paymentMethodToSelect.Selected = true;
            }
            //if no option has been selected, let's do it for the first one
            if (model.PaymentMethods.Where(so => so.Selected).FirstOrDefault() == null)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                    paymentMethodToSelect.Selected = true;
            }

            return model;
        }


        public ActionResult SelectPaymentMethod(string paymentMethodName)
        {
            //validation
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.ToList();
            if (cart.Count == 0)
                return RedirectToRoute("ShoppingCart");

       
            if ((_workContext.CurrentCustomer.IsGuest() ))
                return new HttpUnauthorizedResult();

          
           

            //payment method 
            if (String.IsNullOrEmpty(paymentMethodName))
                return RedirectToAction("PaymentMethod");

  

            //save
            _workContext.CurrentCustomer.SelectedPaymentMethodSystemName = paymentMethodName;
            _customerService.UpdateCustomer(_workContext.CurrentCustomer);

            return RedirectToAction("Confirm");
        }

        #endregion


        #region confirm order
        public ActionResult Confirm()
        {
            var cart = GetCustomerShoppingCartItems(_workContext.CurrentCustomer.Id);

            if (cart.Count == 0)
                return RedirectToRoute("ShoppingCart");

            

            if ((_workContext.CurrentCustomer.IsGuest() ))
                return new HttpUnauthorizedResult();

            //model
            var model = PrepareConfirmOrderModel(cart);
            ViewBag.Model = model;
            return View(model);
        }

        protected CheckoutConfirmModel PrepareConfirmOrderModel(IList<ShoppingCartItem> cart)
        {
            var model = new CheckoutConfirmModel();


            var shoppingCartModel= new ShoppingCartModel();

            foreach (var shoppingCartItem in cart)
            {
                var pv = _productService.GetProductVariantById(shoppingCartItem.ProductVariantId);


                var shoppingCartItemModel = new ShoppingCartItemModel()
                {
                    AttributeInfo = formatter.ToFormattedString(shoppingCartItem.AttributesXml),
                    PictureUrl = _pictureService.GetPictureUrl(pv.PictureId, 100, false),
                    ProductVariantId = pv.Id,
                    ProductId = pv.Product.Id,
                    ProductName = pv.Product.ProductName,
                    Quantity = shoppingCartItem.Quantity,
                    Sku = pv.Sku,
                    SubTotal = pv.Price * shoppingCartItem.Quantity,
                    UnitPrice = pv.Price,
                };

                shoppingCartModel.Items.Add(shoppingCartItemModel);

            }

            model.ShoppingCartModel = shoppingCartModel;
            return model;

          
        }

        public ActionResult ConfirmOrder()
        {
            //validation
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.ToList();
            if (cart.Count == 0)
                return  Redirect("/ShoppingCart/cart");

      

            if (_workContext.CurrentCustomer.IsGuest())
                return new HttpUnauthorizedResult();


            //model
            var model = new CheckoutConfirmModel();
            model.Warnings = new List<string>();
            try
            {
        
                //place order
                var processPaymentRequest = new ProcessPaymentRequest();
                processPaymentRequest.CustomerId = _workContext.CurrentCustomer.Id;
                processPaymentRequest.PaymentMethodSystemName = _workContext.CurrentCustomer.SelectedPaymentMethodSystemName;
                var placeOrderResult = _orderProcessingService.PlaceOrder(processPaymentRequest);
                if (placeOrderResult.Success)
                {
                    //_httpContext.Session["OrderPaymentInfo"] = null;
                    var postProcessPaymentRequest = new PostProcessPaymentRequest()
                    {
                        Trading = placeOrderResult.PlacedTrading
                    };
                    _paymentService.PostProcessPayment(postProcessPaymentRequest);

                    return RedirectToAction("Completed");
                }
                else
                {
                    foreach (var error in placeOrderResult.Errors)
                        model.Warnings.Add(error);
                }
            }
            catch (Exception exc)
            {
                _logger.Warning(exc.Message, exc);
                model.Warnings.Add(exc.Message);
            }

            //If we got this far, something failed, redisplay form
            return View(model);
        }


        public ActionResult Completed(int? orderId)
        {
            //validation
            if ((_workContext.CurrentCustomer.IsGuest() ))
                return new HttpUnauthorizedResult();

            //model
            var model = new CheckoutCompletedModel();

            Order order = null;
            if (orderId.HasValue)
            {
                //load order by identifier (if provided)
                order = _orderService.GetOrderById(orderId.Value);
            }
            if (order == null)
            {
                order = _orderService
                    .GetOrdersByCustomerId(_workContext.CurrentCustomer.Id)
                    .FirstOrDefault();
            }
            if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId)
            {
                return RedirectToRoute("HomePage");
            }

            model.OrderId = order.Id;

            return View(model);
        }

        #endregion

    }
}
